-- UINewAirShipList
-- Create by dengc
-- 天空之城飞艇列表界面

-- UINewAirShipList继承自Layer
UINewAirShipList = class("UINewAirShipList", function()
    return cc.Layer:create();
end);

function UINewAirShipList.create()
    return UINewAirShipList.new();
end

-- 内部函数声明
local itemWidthGap      = 320;
local itemheightGap     = 0;
local GROUP_DEVICE_NUM  = 4; -- 每组改造项所拥有的装置数量
local airShipList       = {};

-- 构造函数
function UINewAirShipList:ctor()
    -- 初始化
    self:setName("UINewAirShipList");
    local node = cc.CSLoader:createNode("layout/sky_city/NewSkyCityGroup.csb");
    self:addChild(node);
    self.node = node;

    self.panel = findChildByName(self.node, "CT/panel");
    self.bottomPanel = findChildByName(self.node, "CT/bottom_panel");

    -- 前一界面信息
    self.lastUIType = "normal";
    self.lastUIPage = 4;
    self.lastUIIndex = 1;

    -- 注册事件处理回调函数
    self:registerEventCallback();

    -- 初始化
    self:initData();
    self:initGrid();

    -- 重绘
    self:redraw();

    self:appearFromCenter();

    -- 注册点击事件
    self:registerTouchEvent();

    -- 适配
    self:resize();
end

-- 适配
function UINewAirShipList:resize()
    local node = self.node;

    -- bg居中显示并充满整个屏幕
    AlignM.fitToScreen(node, "bg");
    AlignM.fitToScreen(node, "bg2");

    -- CT居中并缩放至合适大小
    AlignM.alignToCenter(node, "CT");

    -- BT置于底部并缩放至合适大小
    AlignM.alignToBottomCenter(node, "BT");

    local CT = findChildByName(self.node, "CT");
    local panelBg = findChildByName(self.node, "CT/bg");
    local CTScale = CT:getScale();
    local w = AlignM.frameSize.width;
    local h = AlignM.frameSize.height;

    panelBg:setScaleX(w / DESIGN_WIDTH / CTScale);
    panelBg:setScaleY(h / DESIGN_HEIGHT / CTScale);

    AlignM.alignToTopCenter(node, "Top");

    -- BT2置于底部并缩放至合适大小
    AlignM.alignToBottomCenter(node, "BT2");
end

-- 重绘界面
function UINewAirShipList:redraw()
    local shipId = airShipList[self.selectIndex];

    -- 绘制标题栏
    self:redrawTitle();

    -- 绘制分组详细信息
    self:redrawDetailInfo();

    -- 绘制容器内的item
    self:redrawGroupItems();

    -- 绘制按钮
    self:redrawButton();

    local armamentNode = findChildByName(self.node, "CT/armament_node");
    local reticleNode = findChildByName(self.node, "CT/reticle_node");

    if shipId == NewAirShipM.getActiveAirShip() then
        -- 准心的特效
        self:playReticleEffect();
        -- 绘制主炮
        self:redrawArmament();

        -- 播放主炮、副炮信息出现效果
        self:playArmamentEffect();
    else
        armamentNode:setVisible(false);
        reticleNode:setVisible(false);
    end
end

-- 绘制主炮
function UINewAirShipList:redrawArmament()
    local armamentNode = findChildByName(self.node, "CT/armament_node");
    armamentNode:setVisible(true);
    armamentNode:setScale(1);

    local techNode = findChildByName(armamentNode, "tech_node");
    local specialNode = findChildByName(armamentNode, "special_node");
    local magicNode = findChildByName(armamentNode, "magic_node");
    local skillList = NewAirShipM.getArmament();
    local shipId = NewAirShipM.getActiveAirShip();
    local mainSkill = NewAirShipM.query(shipId, "physic_skill");

    for index, node in ipairs({ techNode, specialNode, magicNode}) do
        local info = skillList[index];
        local skillType = getLocStr("airship_skill_type" .. index);
        local label = findChildByName(node, "text");
        label.index = index;
        label:setFontSize(TextStyleM.TEXT_SIZE_TINY);
        label:setTextColor(TextStyleM.TEXT_COLOR_BRIGHT_BLUE);
        label:setScale(0.85);
        --TextStyleM.setTextStyle(label,TextStyleM.TEXT_SIZE_DATE, TextStyleM.TEXT_COLOR_BRIGHT_BLUE);

        if NewAirShipM.isActiveWingman(shipId) then
            node:setVisible(true);
        else
            if index == NewAirShipM.query(shipId, "skill_type") then
                node:setVisible(true);
            else
                node:setVisible(false);
            end
        end
        if info then
            -- 有数据
            local shipId = info["ship_id"];
            local skillId = info["skill_id"];
            local skillLevel = info["skill_level"] + 1;

            -- 主炮/副炮
            local armamentType;
            if NewAirShipM.query(shipId, "skill_type") == index then
                armamentType = getLocStr("airship_main_skill");
            else
                armamentType = getLocStr("airship_wingman_skill");
            end

            local skillName = SkyShipSkillM.query(skillId, "name");
            local str = string.format(getLocStr("airship_armament"),
                skillType, skillName, skillLevel)
            label:setString(str);
            label:setOpacity(255);

            label.skillId = skillId;
        else
            -- 没有数据
            local str = string.format(getLocStr("airship_armament_no"), skillType);
            label:setString(str);
            label:setOpacity(150);

            label.skillId = 0;
        end

        -- 默认可以显示的宽度为200
        -- 如果文本的宽度超过默认宽度，则缩小下字体大小
        local width = label:getContentSize().width;
        local scale = width / 200;
        if scale < 1 then
            scale = 1;
        end

        label:setFontSize(TextStyleM.TEXT_SIZE_TINY / scale);
    end
end

-- 播放主炮、副炮信息出现效果
function UINewAirShipList:playArmamentEffect()
    local armamentNode = findChildByName(self.node, "CT/armament_node");
    local techNode = findChildByName(armamentNode, "tech_node");
    local specialNode = findChildByName(armamentNode, "special_node");
    local magicNode = findChildByName(armamentNode, "magic_node");
    local infoNodeList = { specialNode, magicNode, techNode, };

    for i = 1, #infoNodeList do
        local node = infoNodeList[i];
        local label = findChildByName(node, "text");
        node:setScale(0.1);
        node:setOpacity(0);
        node:stopAllActions();
        label:stopAllActions();
        local delayTime = 0.1 * i;

        local delay     = cc.DelayTime:create(delayTime);
        local fadeIn    = cc.FadeIn:create(0.3);
        local scaleUp1  = cc.ScaleTo:create(0.3, 1.2);
        local scaleDown = cc.ScaleTo:create(0.1, 0.95);
        local scaleUp2  = cc.ScaleTo:create(0.05, 1);
        local callFunc  = cc.CallFunc:create(function ()
            if label.skillId == 0 then
                local fadeTo1 = cc.FadeTo:create(0.8, 200);
                local delay1 = cc.DelayTime:create(0.1);
                local fadeTo2 = cc.FadeTo:create(0.8, 80);
                local delay2 = cc.DelayTime:create(0.1);
                label:runAction(cc.RepeatForever:create(cc.Sequence:create(fadeTo1, delay1, fadeTo2, delay2)));
            end
        end);

        node:runAction(cc.Sequence:create(delay, cc.Spawn:create(fadeIn, scaleUp1), scaleDown, scaleUp2, callFunc));

        local sequareNode = findChildByName(node, "sequare");
        sequareNode:setOpacity(150);
    end
end

-- 播放新副炮选中效果
function UINewAirShipList:playNewArmamentEffect(shipId)
    local armamentNode = findChildByName(self.node, "CT/armament_node");
    local techNode = findChildByName(armamentNode, "tech_node");
    local specialNode = findChildByName(armamentNode, "special_node");
    local magicNode = findChildByName(armamentNode, "magic_node");
    local infoNodeList = { techNode, specialNode, magicNode, };
    local skillType = NewAirShipM.query(shipId, "skill_type");

    local node = infoNodeList[skillType];
    local label = findChildByName(node, "text");
    label:stopAllActions();

    node:setScale(0.01);
    local scaleTo1 = cc.ScaleTo:create(0.3, 1.2);
    local scaleTo2 = cc.ScaleTo:create(0.2, 0.95);
    local scaleTo3 = cc.ScaleTo:create(0.1, 1);
    node:runAction(cc.Sequence:create(scaleTo1, scaleTo2, scaleTo3));
end

-- 播放准心的特效
function UINewAirShipList:playReticleEffect()
    local reticleNode = findChildByName(self.node, "CT/reticle_node");
    local reticleNode1 = findChildByName(reticleNode, "reticle1");
    local reticleNode2 = findChildByName(reticleNode, "reticle2");
    local reticleNode3 = findChildByName(reticleNode, "reticle3");
    local reticleNode4 = findChildByName(reticleNode, "reticle4");
    local reticleNode5 = findChildByName(reticleNode, "reticle5");

    if not reticleNode.initScale then
        reticleNode.initScale = reticleNode:getScale();
    end
    local initScale = reticleNode.initScale;
    -- 因为消失特效是变小，这里重置下比例尺
    reticleNode:setScale(initScale);
    reticleNode:setOpacity(150);

    -- 先暂停下所有准心图片的行为
    reticleNode:stopAllActions();
    reticleNode1:stopAllActions();
    reticleNode2:stopAllActions();
    reticleNode3:stopAllActions();
    reticleNode4:stopAllActions();
    reticleNode5:stopAllActions();

    -- 如果正在播光效，那就先把光效移除掉
    if reticleNode.effectNode then
        reticleNode:removeChild(reticleNode.effectNode);
        reticleNode.effectNode = nil;
    end

    reticleNode:setVisible(true);
    reticleNode1:setVisible(false);
    reticleNode2:setVisible(false);
    reticleNode3:setVisible(false);
    reticleNode4:setVisible(false);
    reticleNode5:setVisible(false);

    local function frameEventFunc(frame)
        if frame.getEvent and frame:getEvent() == "pilor" then
            local index = frame:getFrameIndex();

            if index == 32 then
                reticleNode.effectNode:setVisible(false);
                reticleNode1:setVisible(true);
                reticleNode2:setVisible(true);
                reticleNode3:setVisible(true);
                reticleNode4:setVisible(true);
                reticleNode5:setVisible(true);
                reticleNode1:setScale(1);
                reticleNode2:setScale(1);
                reticleNode3:setRotation(0);
                reticleNode4:setRotation(0);
                reticleNode5:setScale(1);

                -- 缩小后放大
                local delay1 = cc.DelayTime:create(0.4);
                local scaleDown1 = cc.ScaleTo:create(0.7, 0.7);
                local scaleUp1 = cc.ScaleTo:create(0.7, 1);

                -- 放大后缩小
                local delay2 = cc.DelayTime:create(0.4);
                local scaleUp2 = cc.ScaleTo:create(0.7, 1.3);
                local scaleDown2 = cc.ScaleTo:create(0.7, 1);

                -- 右转后左转
                local delay3 = cc.DelayTime:create(0.4);
                local rotateRight3 = cc.RotateBy:create(2, 90);
                local rotateLeft3 = cc.RotateBy:create(2, -90);

                -- 左转后右转
                local delay4 = cc.DelayTime:create(0.4);
                local rotateLeft4 = cc.RotateBy:create(2, -90);
                local rotateRight4 = cc.RotateBy:create(2, 90);

                -- 小幅度的放大后缩小
                local delay5 = cc.DelayTime:create(0.4);
                local scaleUp5 = cc.ScaleTo:create(1, 1.05);
                local scaleDown5 = cc.ScaleTo:create(1, 1);

                reticleNode1:runAction(cc.RepeatForever:create(cc.Sequence:create(delay1, scaleDown1, scaleUp1)));
                reticleNode2:runAction(cc.RepeatForever:create(cc.Sequence:create(delay2, scaleUp2, scaleDown2)));
                reticleNode3:runAction(cc.RepeatForever:create(cc.Sequence:create(delay3, rotateRight3, rotateLeft3)));
                reticleNode4:runAction(cc.RepeatForever:create(cc.Sequence:create(delay4, rotateLeft4, rotateRight4)));
                reticleNode5:runAction(cc.RepeatForever:create(cc.Sequence:create(delay5, scaleUp5, scaleDown5)));
            end
        end
    end

    local _, effectNode = playEffect(reticleNode, 1802, 0, 0, frameEventFunc);
    effectNode:setVisible(true);
    reticleNode.effectNode = effectNode;
end

-- 绘制标题栏
function UINewAirShipList:redrawTitle()
    local shipId = airShipList[self.selectIndex];

    -- 飞艇名称
    local titleLabel = findChildByName(self.node, "Top/title_bar/title");
    titleLabel:setString(NewAirShipM.query(shipId, "name"));
    TextStyleM.setArtWordTitleStyle(titleLabel);

    -- 阶位(星级)
    local starNode = findChildByName(self.node, "Top/title_bar/star_node");
    local lightStarPath = "images/ui/symbol/star_large.png";
    local darkStarPath  = "images/ui/symbol/star_large2.png";

    -- 未建造，显示初始星级
    local starNum = 0;
    local maxStarNum = NewAirShipM.getMaxRank(shipId);
    if not NewAirShipM.hasOwnShip(shipId) then
        starNum = NewAirShipM.query(shipId, "init_rank");
    else
        starNum = NewAirShipM.getAirShipRank(shipId);
    end

    local layer = createStarLayerEx(starNum, maxStarNum, lightStarPath, darkStarPath);

    if layer then
        starNode:removeAllChildren();
        starNode:addChild(layer);
    end
end

-- 绘制底部按钮
function UINewAirShipList:redrawButton()
    local shipId = airShipList[self.selectIndex];
    -- 如果是未建造的飞艇，显示建造按钮，否则显示出战按钮
    local btnActived = findChildByName(self.node, "BT/btn_actived");
    TextStyleM.setTextStyle(btnActived, TextStyleM.TEXT_SIZE_MIDDLE, TextStyleM.TEXT_COLOR_BROWN_YELLOW, true);
    if not NewAirShipM.hasOwnShip(shipId) then
        btnActived:setTitleText(getLocStr("btn_text_make"));
    else
        btnActived:setTitleText(getLocStr("btn_text_actived"));
    end

    -- 出战按钮
    local btnActived = findChildByName(self.node, "BT/btn_actived");
    if shipId == NewAirShipM.getActiveAirShip() then
        btnActived:setBright(false);
        btnActived:setTouchEnabled(false);
    else
        btnActived:setBright(true);
        btnActived:setTouchEnabled(true);
    end

    -- 图鉴按钮
    local btnTeam = findChildByName(self.node, "BT/btn_team");
    TextStyleM.setTextStyle(btnTeam, TextStyleM.TEXT_SIZE_MIDDLE, TextStyleM.TEXT_COLOR_BROWN_YELLOW, true);
    btnTeam:setTitleText(getLocStr("slimes_handbook"));
end

-- 绘制分组详细信息
function UINewAirShipList:redrawDetailInfo()
    local shipId        = airShipList[self.selectIndex];
    local shipInfo      = NewAirShipM.getUserAirShipInfoWithoutProp(shipId);
    local shipConfig    = NewAirShipM.query(shipId);
    local airships      = ME.user.dbase:query("airships") or {};
    local airshipInfo   = airships[shipId] or {};
    local detailNode    = findChildByName(self.node, "BT2/detail_node");
    local haloLabel     = findChildByName(detailNode, "halo_name");
    local activedLabel  = findChildByName(detailNode, "actived");
    local haloDescLabel = findChildByName(detailNode, "halo_desc");
    local levelLabel    = findChildByName(detailNode, "level");

    -- 如果飞船尚未建造，那么将无法获得shipInfo，这里初始化为初始属性
    if not shipInfo then
        shipInfo = {
            ["fire"]    = shipConfig["init_fire"],
            ["armor"]   = shipConfig["init_armor"],
            ["speed"]   = shipConfig["init_speed"],
            ["luck"]    = shipConfig["init_luck"],
        };
    end

    -- 飞艇光环及是否出战
    TextStyleM.setTextStyle(haloLabel,TextStyleM.TEXT_SIZE_SMALL, TextStyleM.TEXT_COLOR_DARK_RED);
    TextStyleM.setTextStyle(activedLabel,TextStyleM.TEXT_SIZE_SMALL2, TextStyleM.TEXT_COLOR_BLUE);

    local ringsSkillId = NewAirShipM.getAirShipSkillId(shipId);
    local ringRank = NewAirShipM.getRingsLevel(shipId);
    local realSkillId = SkillM.findSkill(ringsSkillId, ringRank);

    haloLabel:setString(SkillM.query(ringsSkillId, "name"));

    local w = getRealContentSize(haloLabel).width;
    activedLabel:setPositionX(haloLabel:getPositionX() + w);

    if not NewAirShipM.hasOwnShip(shipId) then
        -- 未建造
        levelLabel:setVisible(false);
        TextStyleM.setTextStyle(activedLabel,TextStyleM.TEXT_SIZE_SMALL2, TextStyleM.TEXT_COLOR_GRAY);
        activedLabel:setString(getLocStr("not_make"));
    else
        -- 光环等级
        levelLabel:setVisible(false);
        TextStyleM.setTextStyle(activedLabel,TextStyleM.TEXT_SIZE_SMALL2, TextStyleM.TEXT_COLOR_DARK_RED);
        activedLabel:setString(getLevelStr(NewAirShipM.getRingsLevel(shipId)));
        local offsetX = haloLabel:getVirtualRenderer():getContentSize().width + 5;
        activedLabel:setPositionX(haloLabel:getPositionX() + offsetX);
    end

    -- 飞艇光环描述
    -- 获取飞艇的光环技能id
    local ringDesc = SkillM.getSkillDesc(realSkillId, true, "normal");
    TextStyleM.setTextStyle(haloDescLabel, TextStyleM.TEXT_SIZE_MINI, TextStyleM.TEXT_COLOR_DARK_BROWN, nil, nil, nil, nil, nil, nil, nil, TextStyleM.getTextScale(ringDesc, 21 * 2));
    haloDescLabel:setString(ringDesc);

    -- 绘制飞艇的属性栏
    self:redrawAirShipAttrib();

    -- 飞艇的自带技能图标
    local skillImg = findChildByName(detailNode, "skill");
    skillImg:setVisible(true);
    local physicSkill = NewAirShipM.query(shipId, "physic_skill");
    skillImg:loadTexture(getAirShipSkillIconPath(SkyShipSkillM.query(physicSkill, "icon")));
    skillImg:setScale(0.9);

    -- 飞艇技能等级
    local skillLevel = NewAirShipM.getCannonLevel(shipId) + 1;
    local skillLabel = findChildByName(detailNode, "skill_level");
    if NewAirShipM.hasOwnShip(shipId) then
        skillLabel:setVisible(true);
        TextStyleM.setTextStyle(skillLabel, TextStyleM.TEXT_SIZE_TINY, TextStyleM.TEXT_COLOR_LIGHT_BLUE, true, -3);
        local value = getLevelStr(skillLevel);
        skillLabel:setString(value);
    else
        skillLabel:setVisible(false);
    end

    -- 技能背景动画
    local skillBg = findChildByName(detailNode, "skill_bg");
    skillBg:setScale(1.2);
    local rotateForever = cc.RepeatForever:create(cc.RotateBy:create(30, 360));
    skillBg:runAction(rotateForever);
end

-- 绘制飞船属性
function UINewAirShipList:redrawAirShipAttrib()
    local detailNode    = findChildByName(self.node, "BT2/detail_node");
    local chipNode      = findChildByName(detailNode, "chip_node");
    local fragmentNode  = findChildByName(detailNode, "relic_fragment_node");
    local fireNode      = findChildByName(detailNode, "fire_node");
    local armorNode     = findChildByName(detailNode, "armor_node");
    local speedNode     = findChildByName(detailNode, "speed_node");
    local luckNode      = findChildByName(detailNode, "luck_node");

    local shipId        = airShipList[self.selectIndex];
    local shipInfo      = NewAirShipM.getUserAirShipInfoWithoutProp(shipId);

    if NewAirShipM.hasOwnShip(shipId) then
        -- 如果已经拥有该飞船
        -- 显示四维
        self:showFourDimensional(true);

        -- 绘制四维和总战力，出战冈布奥数量
        local nodeList = { fireNode, armorNode, speedNode, luckNode, };
        local attribStrList = { getLocStr("airship_fire"), getLocStr("airship_armor"), getLocStr("airship_speed"),
            getLocStr("airship_luck"), };

        local valueList = {
            shipInfo["fire"],
            shipInfo["armor"],
            shipInfo["speed"],
            shipInfo["luck"],};

        for index, node in ipairs(nodeList) do
            local attribLabel = findChildByName(node, "attrib");
            local valueLabel = findChildByName(node, "value");

            if index >= 5 then
                TextStyleM.setTextStyle(attribLabel, TextStyleM.TEXT_SIZE_MINI, TextStyleM.TEXT_COLOR_BEIGE, false, -1);
            else
                TextStyleM.setTextStyle(attribLabel, TextStyleM.TEXT_SIZE_TINY, TextStyleM.TEXT_COLOR_BEIGE, false, -1);
            end
            TextStyleM.setTextStyle(valueLabel, TextStyleM.TEXT_SIZE_TINY, TextStyleM.TEXT_COLOR_BEIGE, false, -1);

            attribLabel:setString(attribStrList[index]);
            valueLabel:setString(valueList[index]);
        end
    else
        -- 还未拥有
        -- 隐藏四维
        self:showFourDimensional(false);

        -- 绘制飞艇属性
        local nodeList = { chipNode, fragmentNode, };
        local name = ItemM.query(NewAirShipM.query(shipId, "chip_id"), "name");
        local attribStrList = { name, getLocStr("relic_fragment"), };

        -- 赋值并改变颜色
        local fragmentId = ITEM_ID_RELIC;
        local chipId = NewAirShipM.query(shipId, "chip_id");
        local cost = NewAirShipM.query(shipId, "cost");
        local needValue1 = cost and cost[chipId] or 0;
        local needValue2 = cost and cost[fragmentId] or 0;
        local curValueList = {ItemM.getAmount(ME.user, chipId), ItemM.getAmount(ME.user, fragmentId)};
        local needValueList = {needValue1, needValue2};

        for index, node in ipairs(nodeList) do
            local attribLabel = findChildByName(node, "attrib");
            local valueLabel = findChildByName(node, "value");
            local needValueLabel = findChildByName(node, "need_value");

            -- 设置名称
            TextStyleM.setTextStyle(attribLabel, TextStyleM.TEXT_SIZE_TINY, TextStyleM.TEXT_COLOR_BEIGE, false, -1);
            attribLabel:setString(attribStrList[index]);

            -- 设置芯片的图标
            if index == 1 then
                local chipId = NewAirShipM.query(shipId, "chip_id");
                local iconId = ItemM.query(chipId, "icon");
                local chipIcon = findChildByName(node, "icon");
                chipIcon:loadTexture(getItemIconPath(iconId));
                chipIcon:setScale(0.42);
            end

            -- 设置需要数量
            TextStyleM.setTextStyle(needValueLabel, TextStyleM.TEXT_SIZE_TINY, TextStyleM.TEXT_COLOR_BEIGE, false, -1);
            needValueLabel:setString("/" .. needValueList[index]);
            setNextTextPosX(needValueLabel, valueLabel, 0);

            -- 设置当前数量，不足时设置为红色
            if curValueList[index] < needValueList[index] then
                TextStyleM.setTextStyle(valueLabel, TextStyleM.TEXT_SIZE_TINY, TextStyleM.TEXT_COLOR_WHITE, false, -1);
                valueLabel:setTextColor(TextStyleM.TEXT_COLOR_LIGHT_RED);
                valueLabel:setString(curValueList[index]);
            else
                TextStyleM.setTextStyle(valueLabel, TextStyleM.TEXT_SIZE_TINY, TextStyleM.TEXT_COLOR_BEIGE, false, -1);
                valueLabel:setString(curValueList[index]);
            end
        end
    end
end

-- 显示飞艇四维
function UINewAirShipList:showFourDimensional(isShow)
    local detailNode    = findChildByName(self.node, "BT2/detail_node");
    local chipNode      = findChildByName(detailNode, "chip_node");
    local fragmentNode  = findChildByName(detailNode, "relic_fragment_node");
    local fireNode      = findChildByName(detailNode, "fire_node");
    local armorNode     = findChildByName(detailNode, "armor_node");
    local speedNode     = findChildByName(detailNode, "speed_node");
    local luckNode      = findChildByName(detailNode, "luck_node");

    fireNode:setVisible(isShow);
    armorNode:setVisible(isShow);
    speedNode:setVisible(isShow);
    luckNode:setVisible(isShow);

    local nagative = not isShow;
    chipNode:setVisible(nagative);
    fragmentNode:setVisible(nagative);
end

-- 计算index代表的分组item和指定的分组的距离
function UINewAirShipList:calcDistance(index, targetIndex)
    local selectIndex = targetIndex or self.selectIndex;

    local fristIndex = index - selectIndex
    local secondIndex = index + #airShipList - selectIndex;
    local thridIndex = index - #airShipList - selectIndex;

    local minDistance = math.min(math.abs(fristIndex), math.abs(secondIndex), math.abs(thridIndex));
    if minDistance == math.abs(fristIndex) then
        return fristIndex;
    elseif minDistance == math.abs(secondIndex) then
        return secondIndex;
    elseif minDistance == math.abs(thridIndex) then
        return thridIndex;
    end
end

-- 计算Index代表的分组item在指定的分组为选中分组情况下的坐标
function UINewAirShipList:calcItemPos(index, targetIndex)
    local selectIndex = targetIndex or self.selectIndex;
    local distance = self:calcDistance(index, selectIndex);
    local origin = { ["x"] = self.panel:getContentSize().width / 2, ["y"] = self.panel:getContentSize().height / 2, };

    return cc.p(origin.x + distance * itemWidthGap, origin.y - 20 + math.abs(distance) * itemheightGap);
end

-- 计算Index代表的分组item在指定的分组为选中分组情况下的比例
function UINewAirShipList:calcItemScale(index, targetIndex)
    local selectIndex = targetIndex or self.selectIndex;
    local distance = self:calcDistance(index, selectIndex);

    return math.pow(0.8, math.abs(distance)) * 0.9;
end

-- 绘制容器内的item
function UINewAirShipList:redrawGroupItems(needRedraw)
    -- 绘制分组item
    local function redrawItem(node, index)
        local shipId = airShipList[index];
        local airShipConfig = NewAirShipM.query(shipId);
        local effectNode = findChildByName(node, "effect");
        local airshipImg = findChildByName(node, "airship");
        local descLabel  = findChildByName(node, "desc");
        descLabel:setVisible(false);
        effectNode:removeAllChildren();

        -- 飞艇光效
        local shipEffect = airShipConfig["fly_effect"];

        if NewAirShipM.hasOwnShip(shipId) then
            if type(shipEffect) == "number" then
                local _, effect = playEffect(effectNode, shipEffect);
                node.effect = effect;

                effectNode:setVisible(true);
                airshipImg:setVisible(false);
            else
                effectNode:setVisible(false);
                airshipImg:setVisible(true);

                -- 飞艇图标
                airshipImg:loadTexture(getAirShipImgPath(airShipConfig["icon"]));
            end
        else
            effectNode:setVisible(false);
            airshipImg:setVisible(true);

            -- 飞艇图标
            airshipImg:loadTexture(getAirShipBlueprintImgPath(airShipConfig["icon"]));
        end
    end

    -- 在bottomPanel绘制所有飞艇
    for i = 1, #airShipList do
        local child = findChildByName(self.bottomPanel, "item" .. i);
        local descLabel = findChildByName(child, "desc");

        child:setPosition(self:calcItemPos(i));
        child:setScale(self:calcItemScale(i));

        descLabel:setVisible(false);
        -- 绘制下内容
        if needRedraw or not child.hasInit then
            redrawItem(child, i);
            child.hasInit = true;
        end

        -- 当前选中的分组不显示，其他的全部显示
        if i == self.selectIndex or math.abs(self:calcDistance(i)) > 2 then
            child:setVisible(false);
        else
            child:setVisible(true);
            local remouldBubble = findChildByName(child, "bubble");
            remouldBubble:setVisible(false);
        end
    end

    -- 绘制panel中选中的飞艇
    local child = findChildByName(self.panel, "selectItem");
    --local descLabel = findChildByName(child, "desc");
    local effectNode = findChildByName(child, "effect");
    local airshipImg = findChildByName(child, "airship");

    child:setPosition(self:calcItemPos(self.selectIndex));
    child:setScale(self:calcItemScale(self.selectIndex));

    -- 绘制下内容
    redrawItem(child, self.selectIndex);

    -- 选中的分组要轻微悬浮
    if not child.init then
        playFluctuateAnima(effectNode, 0.1, 1);
        child.init = true;
    end

    -- 尝试显示气泡
    local remouldBubble = findChildByName(child, "bubble");
    local shipId = airShipList[self.selectIndex];
    self:tryShowBubble(remouldBubble, shipId);

    -- 恢复下飞艇的y坐标值
    if not airshipImg.initPosY then
        airshipImg.initPosY = airshipImg:getPositionY();
    end
    airshipImg:setPositionY(airshipImg.initPosY);
    effectNode:setPositionY(airshipImg.initPosY);

    airshipImg:stopAllActions();

    if NewAirShipM.hasOwnShip(shipId) then
        airshipImg:setOpacity(255);
        playFluctuateAnima(airshipImg, 0.1, 1);
    else
        playFluctuateAnima(airshipImg, 0.1, 1);

        airshipImg:setOpacity(100);
        local fadeTo1 = cc.FadeTo:create(1.5, 200);
        local fadeTo2 = cc.FadeTo:create(1.5, 120);
        airshipImg:runAction(cc.RepeatForever:create(cc.Sequence:create(fadeTo1, fadeTo2)));
    end
end

-- 初始化数据
function UINewAirShipList:initData()
    airShipList = NewAirShipM.getCanDrawAirships();
    local activedShip = NewAirShipM.getActiveAirShip();

    -- 做个保护
    if not NewAirShipM.hasOwnShip(activedShip) then
        self.selectIndex = NewAirShipM.getOwnAirShips()[1];
    else
        self.selectIndex = table.indexOf(airShipList, activedShip);
    end

    -- 记录下当前选中的飞船id
    NewAirShipM.setSelectedAirShip(airShipList[self.selectIndex]);
end

-- 初始化分组节点
function UINewAirShipList:initGrid()
    local itemNode = cc.CSLoader:createNode("layout/sky_city/AirShipListItem.csb");
    local widget = replaceNodeWithWidget(itemNode);

    for i = 1, #airShipList do
        local child = widget:clone();
        child:setName("item" .. i);
        self.bottomPanel:addChild(child);
    end

    local child = widget:clone();
    child:setName("selectItem");
    self.panel:addChild(child);
end

-- 移动
function UINewAirShipList:moveItems(direction, callback)
    local delay = 0.2;

    for i = 1, #airShipList do
        local child;
        if i == self.selectIndex then
            child = findChildByName(self.panel, "selectItem");
        else
            child = findChildByName(self.bottomPanel, "item" .. i);
        end

        -- 计算这次移动后，选中的item会变成哪一个
        local nextIndex;
        if direction == 1 then
            nextIndex = self.selectIndex + 1;
            if nextIndex > #airShipList then
                nextIndex = 1;
            end
        elseif direction == -1 then
            nextIndex = self.selectIndex - 1;
            if nextIndex <= 0 then
                nextIndex = #airShipList;
            end
        end

        -- 计算child要移动到哪个位置，比例又是多少
        local curPos = self:calcItemPos(i);
        local desPos = self:calcItemPos(i, nextIndex);
        local movePos = cc.p(direction * -1 * itemWidthGap, desPos.y - curPos.y);

        -- 只有当分组只有4组的时候需要这个特殊处理
        -- 当只有4个分组的情况下无法满足往任意一方移动均可保证另一方向有个分组可以移动进来
        if #airShipList == 4 then
            if direction == 1 then
                if i == self.selectIndex - 2 or i == self.selectIndex + 2 then
                    child:setPositionX(desPos.x + itemWidthGap);
                end
            else
                if i == self.selectIndex - 2 or i == self.selectIndex + 2 then
                    child:setPositionX(desPos.x - itemWidthGap);
                end
            end
        end

        local moveBy = cc.MoveBy:create(delay, movePos);
        local scaleTo = cc.ScaleTo:create(delay, self:calcItemScale(i, nextIndex));
        local callFunc = cc.CallFunc:create(function()
            child:setVisible(true);
        end);
        child:runAction(cc.Sequence:create(callFunc, cc.Spawn:create(moveBy, scaleTo)));
    end

    performWithDelay(self, callback, delay);

    -- 播放准心和炮台信息缩小淡出效果
    local armamentNode = findChildByName(self.node, "CT/armament_node");
    local reticleNode = findChildByName(self.node, "CT/reticle_node");

    if armamentNode:isVisible() and reticleNode:isVisible() then
        for _, node in ipairs({armamentNode, reticleNode}) do
            node:stopAllActions();
            local scaleTo = cc.ScaleTo:create(0.1, 0.01);

            node:runAction(cc.Sequence:create(scaleTo));
        end
    end
end

-- 注册事件处理回调函数
function UINewAirShipList:registerEventCallback()
    -- 界面析构后，需要清理下
    self:registerScriptHandler(function(eventType)
        if eventType == "exit" then
            EventMgr.removeAll("UINewAirShipList");
        elseif eventType == "enter" then

        end
    end);

    -- 注册获得焦点的回调
    EventMgr.register("UINewAirShipList", event.FOCUS_CHANGED, function(para)
        if para["get"] == "UINewAirShipList" then
            local btNode = findChildByName(self.node, "BT");
            btNode:setVisible(true);

            UIMgr:getCurrentScene().topMenu:show(TOPMENU_FRAME_RELIC_FRAGMENT, TOPMENU_FRAME_AIRSHIP_ATTRIB2, TOPMENU_FRAME_HEAD_AIRSHIP);
        elseif para["lose"] == "UINewAirShipList" then
            local btNode = findChildByName(self.node, "BT");
            btNode:setVisible(false);
        end
    end);

    -- 状态刷新
    EventMgr.register("UINewAirShipList", event.USER_INFO_UPDATED, function(args)
        if args == "active_airship" then
            self:redraw();
            self:palyShipActivedEffect("active_airship");
        elseif args == "airships" or args == "new_airships" then
            self:redrawGroupItems(true);
            self:redrawDetailInfo();
            self:redrawButton();
            self:palyShipActivedEffect("new_airships");
        --[[elseif args == "airship_wingman" then
            self:redrawArmament();
            self:playNewArmamentEffect();]]
        end
    end);

    -- 建造飞艇成功
    EventMgr.register("UINewAirShipList", event.MAKE_AIRSHIP_SUCCESS, function(args)
        local shipId = args["ship_id"];
        ME.user.dbase:setTemp("gain_ship_id", shipId);
        self:openGainEffect(shipId);
    end);

    -- 派遣飞艇
    EventMgr.register("UINewAirShipList", event.AIRSHIP_WINGMAN, function(args)
        local shipId = args["shipId"]
        self:redrawArmament();
        self:playNewArmamentEffect(shipId);
    end);

    -- 注册购买商品的事件回调(可能会直接购买碎片)
    EventMgr.register("UINewAirShipList", event.DIRECT_BUY_GOODS, function(args)
        alertBuyGoodsTip(args.bonus);

        self:redraw();
    end);
end

-- 注册点击事件
function UINewAirShipList:registerTouchEvent()
    -- 注册返回按钮点击事件
    local btnBack = findChildByName(self.node, "BT/btn_back");
    local function onBackClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            -- 关闭当前界面
            AudioM.playFx("ship_return");
            UIMgr.getCurrentScene():removeFormByName("UINewAirShipList");
        end
    end
    AddBackEventHandler(self, btnBack, onBackClick);
    TextStyleM.setTextStyle(btnBack, TextStyleM.TEXT_SIZE_MIDDLE, TextStyleM.TEXT_COLOR_BROWN_YELLOW, true);
    btnBack:setTitleText(getLocStr("btn_text_back"));

    -- 注册出战/建造按钮点击事件
    local btnActived = findChildByName(self.node, "BT/btn_actived");
    local function onActivedClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            local shipId = airShipList[self.selectIndex];
            if NewAirShipM.hasOwnShip(shipId) then
                -- 出战
                Operation.cmd_airship_set_actived(airShipList[self.selectIndex]);

                AudioM.playFx("airship_battle");
            else
                local cost = NewAirShipM.query(shipId, "cost")
                local classId = SkyResourceM.queryByAlias("relic_scrap", "class_id");
                local chipId = NewAirShipM.query(shipId, "chip_id");

                local callBack;

                local function strengthen()
                    if ItemM.getAmount(ME.user, chipId) < cost[chipId] then
                        -- 弹出芯片不足提示
                        alert(string.format(getLocStr("airship_build_chip_no_enough2"), ItemM.query(chipId, "name")));
                    elseif ItemM.getAmount(ME.user, classId) < cost[classId] then
                        -- 弹出碎片不足提示
                        -- alert(getLocStr("airship_build_no_enough2"));
                        showScrapLackConfirm(cost[classId], callBack, callBack);
                    else
                        -- 建造
                        Operation.cmd_airship_make(shipId);
                    end
                end

                callBack = function(isClose)
                    if isClose then
                        return;
                    end

                    -- 弹出确认提示框
                    local chipNeedNum = ItemM.getAmount(ME.user, chipId) < cost[chipId] and
                        "[red]" .. cost[chipId] .. "[-]" or
                        "[blue]" .. cost[chipId] .. "[-]";
                    local fragmentNeedNum = ItemM.getAmount(ME.user, classId) < cost[classId] and
                        "[red]" .. cost[classId] .. "[-]" or
                        "[blue]" .. cost[classId] .. "[-]";

                    confirm2(CONFIRM_TYPE_OK_CANCEL, getLocStr("airship_build"),
                        string.format(getLocStr("airship_build_cost_tip"), chipNeedNum, ItemM.query(chipId, "name"),
                            fragmentNeedNum, NewAirShipM.query(shipId, "name")), strengthen,
                            nil, nil, nil, {["hideBackBtn"] = true} );
                end

                callBack();
            end
        end
    end
    btnActived:addTouchEventListener(onActivedClick);

    -- 注册图鉴按钮点击事件
    local btnTeam = findChildByName(self.node, "BT/btn_team");
    local function onTeamClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            AudioM.playFx("ship_click");
            -- 根据配置打开飞艇图鉴界面
            require "game/ui/form/sky_city/UIAirShipHandBook"
            local uiForm = UIAirShipHandBook.create();
            UIMgr.getCurrentScene():addForm(uiForm);
        end
    end
    btnTeam:addTouchEventListener(onTeamClick);

    -- panel点击处理
    local function onPanelClick(sender,eventType)
        if self.isMoveing then
            return;
        end

        if eventType == ccui.TouchEventType.ended then
            sender.initMoveX = nil;
        elseif eventType == ccui.TouchEventType.began then
            sender.initMoveX = nil;
        elseif eventType == ccui.TouchEventType.moved then
            local movePos = sender:getTouchMovePosition();
            if not sender.initMoveX then
                sender.initMoveX = movePos.x;
            end

            local direction;
            local moveLen = AlignM.frameSize.width / 10;
            if movePos.x - sender.initMoveX > moveLen then
                -- 往右滑动
                direction = -1;
            elseif movePos.x - sender.initMoveX < -1 * moveLen then
                -- 往左滑动
                direction = 1;
            else
                return;
            end

            -- 先停止点击事件的回调
            self.isMoveing = true;
            sender.initMoveX = movePos.x;

            local function callback()
                self.isMoveing = false;
                if direction == 1 then
                    self.selectIndex = self.selectIndex + 1;
                    if self.selectIndex > #airShipList then
                        self.selectIndex = 1;
                    end
                elseif direction == -1 then
                    self.selectIndex = self.selectIndex - 1;
                    if self.selectIndex <= 0 then
                        self.selectIndex = #airShipList;
                    end
                end

                -- 记录下当前选中的飞船id
                NewAirShipM.setSelectedAirShip(airShipList[self.selectIndex]);

                -- 重绘下
                self:redraw();

                -- 刷新下topMenu
                local uiTop  = UIMgr.getCurrentScene():getFormByName("UITopMenu");
                uiTop:updateNewFragment();
                uiTop:updateNewAirShipInfo();
            end

            -- 移动
            self:moveItems(direction, callback);
            AudioM.playFx("airship_select");
        end
    end

    self.panel:addTouchEventListener(onPanelClick);

    -- 飞艇主炮技能图标
    local skillImg = findChildByName(self.node, "BT2/detail_node/skill");
    local function onSkillClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            AudioM.playFx("ship_click");

            -- 打开秘宝信息界面
            require "game/ui/form/sky_city/UIAirShipSkillExplain"
            local shipId = airShipList[self.selectIndex];
            local skillId = NewAirShipM.query(shipId, "physic_skill");

            UIMgr.getCurrentScene():removeFormByName("UIAirShipSkillExplain");

            -- 1.主炮描述
            local skillDesc = SkyShipSkillM.getShipSkillDesc(skillId);
            local skillLevel = NewAirShipM.getCannonLevel(shipId);
            local realSkillId = SkyShipSkillM.getSkillByLevel(skillId, skillLevel);
            -- 解析一下
            skillDesc = SkyShipSkillM.parseDesc(realSkillId, skillDesc);

            -- 2.主炮类型描述
            local skillType = NewAirShipM.query(shipId, "skill_type");
            local typeDesc = getLocStr("airship_skill_gun" .. skillType);
            typeDesc = string.format(getLocStr("ship_gun_desc_type"), typeDesc);

            -- 3.主炮威力描述
            local valueDesc = SkyShipSkillM.getShipSkillDetail(skillId);
            valueDesc = string.format(getLocStr("ship_gun_desc_value"), valueDesc);

            local title = SkyShipSkillM.query(skillId, "name") .. " Lv.".. skillLevel + 1;
            local desc = skillDesc .. "\n\n[blue]" .. typeDesc .. "[-]" .. "\n[blue]" .. valueDesc .. "[-]";
            local uiform = UIAirShipSkillExplain.create(title, desc, skillLevel + 1);
            UIMgr.getCurrentScene():addForm(uiform);
        end
    end
    skillImg:addTouchEventListener(onSkillClick);

    -- 详情中属性条图标
    local fireBg = findChildByName(self.node, "BT2/detail_node/fire_node/bg");
    local armorBg = findChildByName(self.node, "BT2/detail_node/armor_node/bg");
    local speedBg = findChildByName(self.node, "BT2/detail_node/speed_node/bg");
    local luckBg = findChildByName(self.node, "BT2/detail_node/luck_node/bg");
    local function onAttribClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            AudioM.playFx("ship_click");
            require "game/ui/form/sky_city/UIAirShipDesc"
            -- 打开飞艇说明界面
            local uiForm = UIAirShipDesc.create();
            UIMgr.getCurrentScene():addForm(uiForm);
            AudioM.playFx("button_spell");
        end
    end
    fireBg:addTouchEventListener(onAttribClick);
    armorBg:addTouchEventListener(onAttribClick);
    speedBg:addTouchEventListener(onAttribClick);
    luckBg:addTouchEventListener(onAttribClick);

    -- 飞艇主炮、副炮信息
    local techNode = findChildByName(self.node, "CT/armament_node/tech_node/text");
    local specialNode = findChildByName(self.node, "CT/armament_node/special_node/text");
    local magicNode = findChildByName(self.node, "CT/armament_node/magic_node/text");
    local function onArmamentClick(sender, eventType)

        if eventType == ccui.TouchEventType.ended then
            AudioM.playFx("ship_click");
            local index = sender.index;
            local shipId = NewAirShipM.getActiveAirShip();

            if not NewAirShipM.isActiveWingman(shipId) then
                -- 未建造副炮搭载平台
                return;
            end

            if index == NewAirShipM.query(shipId, "skill_type") then
                -- 如果是主炮，则提示"主炮无法更换！"
                alert(getLocStr("airship_main_skill_tip"));
                return;
            end

            -- 副炮打开飞艇链接界面
            require "game/ui/form/sky_city/UISkyCityWingman"
            -- 打开飞艇说明界面
            local uiForm = UISkyCityWingman.create(index);
            UIMgr.getCurrentScene():addForm(uiForm);
            AudioM.playFx("button_spell");
        end
    end

    techNode:addTouchEventListener(onArmamentClick);
    specialNode:addTouchEventListener(onArmamentClick);
    magicNode:addTouchEventListener(onArmamentClick);

    -- 改造气泡点击事件
    local function onBubbleClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            require "game/ui/form/sky_city/UINewAirShipStrengthen"
            local shipId = airShipList[self.selectIndex];
            local uiForm = UINewAirShipStrengthen.create(shipId);
            UIMgr.getCurrentScene():addForm(uiForm);
        end
    end
    local child = findChildByName(self.panel, "selectItem");
    local remouldBubble = findChildByName(child, "bubble");
    remouldBubble:addTouchEventListener(onBubbleClick);
end

-- 播放出战特效
function UINewAirShipList:palyShipActivedEffect(playType)
    -- 先在panel中创建一个飞艇的静态图
    local panel = self.panel;

    local shipId;
    if playType == "active_airship" then
        shipId = ME.user.dbase:query("active_airship");

    elseif playType == "new_airships" then
        shipId = airShipList[self.selectIndex];
    end

    local airshipImg = ccui.ImageView:create();
    airshipImg:loadTexture(getAirShipImgPath(NewAirShipM.query(shipId, "icon")));
    airshipImg:setPosition(self:calcItemPos(self.selectIndex));
    panel:addChild(airshipImg);

    -- 提示语
    if playType == "active_airship" then
        alert(string.format(getLocStr("activate_group_tip"), NewAirShipM.query(shipId, "name")));
    end

    -- 播放放大并且淡出的特效
    local delay     = 0.5;
    local scaleTo   = cc.ScaleTo:create(delay, 1.3);
    local fadeOut   = cc.FadeOut:create(delay);
    local callFunc  = cc.CallFunc:create(function ()
        airshipImg:removeFromParent();
    end)
    airshipImg:runAction(cc.Sequence:create(cc.Spawn:create(scaleTo, fadeOut), callFunc));
end

-- 隐藏界面元素
function UINewAirShipList:setVisible(isShow)
    local function visibleNode(nodeName, isShow)
        local targetNode = findChildByName(self.node, nodeName);
        targetNode:setVisible(isShow);
    end

    visibleNode("CT", isShow);
    visibleNode("BT", isShow);
end

-- 打开飞艇获得光效界面
function UINewAirShipList:openGainEffect(shipId)
    require "game/ui/form/sky_city/UIAirShipGainEffect";
    UIMgr.getCurrentScene():removeFormByName("UIAirShipGainEffect");
    local uiForm = UIAirShipGainEffect.create(shipId);
    UIMgr.getCurrentScene():addForm(uiForm);
end

--
function UINewAirShipList:appearFromCenter()
    local top = findChildByName(self.node, "Top");

    local bt2 = findChildByName(self.node, "BT2");

    local titleNode = findChildByName(top, "title_bar");
    local descNode = findChildByName(bt2, "detail_node");

    local oldScale = titleNode:getScale();
    local descSale = descNode:getScale();

    -- title
    titleNode:setScale(oldScale * 0.8);
    local scaleUp1 = cc.EaseIn:create(cc.ScaleTo:create(0.2, oldScale * 1.05), 0.4);
    local scaleUp2 = cc.ScaleTo:create(0.05, oldScale);
    titleNode:runAction(cc.Sequence:create(scaleUp1, scaleUp2));

    descNode:setScale(descSale * 0.8);
    local scaleUp3 = cc.EaseIn:create(cc.ScaleTo:create(0.2, descSale * 1.05), 0.4);
    local scaleUp4 = cc.ScaleTo:create(0.05, descSale);
    descNode:runAction(cc.Sequence:create(scaleUp3, scaleUp4));
end

-- 是否显示改造气泡
function UINewAirShipList:isShowRemouldEffect(id)
    -- 没有激活该飞艇
    if not NewAirShipM.hasOwnShip(id) then
        return false;
    end

    -- 有剩余改造项
    if NewAirShipM.hasRemainStrengthenDevice(id) then
        return "can_remould";
    end

    -- 可以进阶
    if NewAirShipM.canUpRank(id) then
        return "can_uprank";
    end

    return false;
end

-- 装置能否显示呼吸效果
function UINewAirShipList:canDevicePlayEffect(shipId, deviceId)
    local item = NewAirShipM.queryStrengthen(shipId, deviceId)[1];
    local classId = item[2];
    if not classId then
        return false;
    end

    -- 已经改造
    local strengthenRecord = NewAirShipM.getStrengthenRecord(shipId) or {};
    local isRemould = (table.indexOf(strengthenRecord, deviceId) ~= -1);
    if isRemould then
        return false;
    end

    -- 包裹里已有该装置
    local isHave = (ItemM.getAmount(ME.user, classId) > 0);
    if isHave then
        return true;
    end

    -- 包裹里没有，但材料足够可以合成
    if NewAirShipM.isMaterialEnough(shipId, deviceId) == true then
        return true;
    end

    return false;
end

-- 尝试显示改造的气泡
function UINewAirShipList:tryShowBubble(remouldBubble, id)
    local icon = findChildByName(remouldBubble, "icon");
    icon:setScale(1.4);

    -- 绘制气泡
    local result = self:isShowRemouldEffect(id);
    if result == "can_remould" then
        remouldBubble:setVisible(true);
        icon:loadTexture(getLargeAttribIconPath("remould"));
    elseif result == "can_uprank" then
        remouldBubble:setVisible(true);
        icon:loadTexture(getLargeAttribIconPath("rank"));
    else
        remouldBubble:setVisible(false);
    end

    -- 材料足够，可以改造时，显示呼吸效果
    remouldBubble:stopAllActions();
    remouldBubble:setScale(0.7);
    local allStrengthenNum = NewAirShipM.getShowGroup(id) * GROUP_DEVICE_NUM;
    for i = 1, allStrengthenNum do
        if self:canDevicePlayEffect(id, i) then
            playBubbleAnima(remouldBubble, false, 0.7, 0.7, 0.75, 0.8, 0.9);
            return;
        end
    end

    -- 可以进阶，显示呼吸效果
    if result == "can_uprank" then
        playBubbleAnima(remouldBubble, false, 0.7, 0.7, 0.75, 0.8, 0.9);
    end
end

-- 根据id设置当前选中飞艇的下标
function UINewAirShipList:setSelectedIndexById(shipId)
    local destIndex;
    local airShipList = NewAirShipM.getCanDrawAirships();
    for index, id in pairs(airShipList) do
        if shipId == id then
            destIndex = index;
        end
    end

    self.selectIndex = destIndex and destIndex or 1;
end

-- BT从中心弹出
function UINewAirShipList:ctPopUpFromCenter()
    local BT = findChildByName(self.node, "BT");
    local BT2 = findChildByName(self.node, "BT2");
    if not BT or not BT2 then
        return;
    end

    local oldScale = BT:getScale();

    -- BT从中心弹出
    BT:setScale(oldScale * 0.8);
    local scaleUp1 = cc.EaseIn:create(cc.ScaleTo:create(0.2, oldScale * 1.05), 0.4);
    local scaleUp2 = cc.ScaleTo:create(0.05, oldScale);
    BT:runAction(cc.Sequence:create(scaleUp1, scaleUp2));

    BT2:setScale(oldScale * 0.8);
    local scaleUp1 = cc.EaseIn:create(cc.ScaleTo:create(0.2, oldScale * 1.05), 0.4);
    local scaleUp2 = cc.ScaleTo:create(0.05, oldScale);
    BT2:runAction(cc.Sequence:create(scaleUp1, scaleUp2));
end
